package com.zslibrary.BusMaster;

import android.content.Context;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;

import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

import com.zslibrary.Enum.StateDefine;
import com.zslibrary.Enum.StateEventDefine;
import com.zslibrary.Protocol.Adjustment;
import com.zslibrary.Protocol.Adjustments;
import com.zslibrary.Protocol.ComponentTest;
import com.zslibrary.Protocol.Machine;
import com.zslibrary.Enum.BoardId;
import com.zslibrary.Enum.ComponentClassDefine;
import com.zslibrary.Enum.GateStatusDefine;
import com.zslibrary.Protocol.JobList;
import com.zslibrary.Pipe.Pipe;
import com.zslibrary.Protocol.MakeProduct;
import com.zslibrary.Protocol.QueryGateStatus;
import com.zslibrary.Protocol.Service;
import com.zslibrary.Protocol.UserCommand;
import com.zslibrary.Protocol.Version;
import com.zslibrary.StateHandle.BusyState;
import com.zslibrary.StateHandle.ErrorState;
import com.zslibrary.StateHandle.GateQueryState;
import com.zslibrary.StateHandle.IdleState;
import com.zslibrary.StateHandle.InitState;
import com.zslibrary.StateHandle.ReconnectState;
import com.zslibrary.StateHandle.StateMachine;
import com.zslibrary.Structure.ComponentStruct;
import com.zslibrary.Structure.ConfigRecipeStrcut;
import com.zslibrary.Structure.ConfigurableComponentStruct;
import com.zslibrary.Structure.CraftBriefStruct;
import com.zslibrary.Structure.ErrorStruct;
import com.zslibrary.Structure.GateStruct;
import com.zslibrary.Structure.HardwareVersionStruct;
import com.zslibrary.Structure.LocalAdjustmentStruct;
import com.zslibrary.Structure.SoftwareVersionStruct;
import com.zslibrary.Structure.TestInfosStruct;
import com.zslibrary.Structure.TestResultStruct;
import com.zslibrary.Structure.UserAdjustmentStruct;
import com.zslibrary.Tools.ZSLog;

public class BusMaster {
    private volatile static BusMaster mSingleInstance = null;
    private static ReentrantLock instanceLock = new ReentrantLock();
    private static Context mContext;
    private static Pipe mPipeline=new Pipe();
    private static Boolean hasStartBus=false;
//    private UserCommand mCommander;
    public StateMachine mStateMachine;
    //public StateMachine currentState;
    public BusMaster(Context context) {
        mContext = context.getApplicationContext();
    }
    //context改为ApplicationContext
    public static BusMaster getInstance(Context context) {
        instanceLock.lock();
        if (mSingleInstance == null) {
            mSingleInstance = new BusMaster(context);
        }
        instanceLock.unlock();
        return mSingleInstance;
    }

    public void startBus(String portStr, String configPath, final UserAdjustmentStruct[] rawUserAdjustment) {
        if(!hasStartBus) {
            if (mPipeline.launchPipe(portStr, BoardId.IO_BOARD, 115200)) {
                mStateMachine = new StateMachine();
                Machine.readMachine(mContext, configPath);
                Adjustments.initAdjustment(mContext, configPath, rawUserAdjustment);
                mStateMachine.registerState(StateDefine.STATE_IDLE, new IdleState(mPipeline));
                mStateMachine.registerState(StateDefine.STATE_GATE_QUERY, new GateQueryState(mPipeline));
                mStateMachine.registerState(StateDefine.STATE_INIT, new InitState(mPipeline));
                mStateMachine.registerState(StateDefine.STATE_ERROR, new ErrorState(mPipeline, new ErrorStruct("ECA_07", true, true)));
                mStateMachine.registerState(StateDefine.STATE_BUSY, new BusyState(mPipeline));
                mStateMachine.registerState(StateDefine.STATE_RECONNECT, new ReconnectState(mPipeline, "ECA_07"));
                mStateMachine.startStateMachine();
                hasStartBus=true;
//            mCommander=new UserCommand(mPipeline,mStateMachine);
            }
        }
    }

    ComponentTest mTest=new ComponentTest();
    private Boolean isCancelDo=false;
    public Boolean componentTest(@ComponentClassDefine.ComponentId int componentId, int funcId) {
//        mCommander.componentTest(componentId,funcId);
        int event=mStateMachine.pauseStateMachine();
        if(event== StateEventDefine.EVT_NONE||event==StateEventDefine.EVT_QUERY_GATE){
            int returnEvent=mTest.componentTest(mPipeline,(short)componentId,(short)funcId);
            if(isCancelDo) {
                isCancelDo=false;
                return true;
            }
            mStateMachine.resumeStateMachine(returnEvent);
            return true;
        }
        mStateMachine.resumeStateMachine(event);
        return false;
    }

    public String[] getTestString(){
        return mTest.getTestString();
    }

    public TestInfosStruct[] getTestInfo(@ComponentClassDefine.ComponentId int componentId) {
        TestInfosStruct[] infos = null;
//        infos=mCommander.getTestInfos(componentId);
        int event=mStateMachine.pauseStateMachine();
        if(event==StateEventDefine.EVT_NONE||event==StateEventDefine.EVT_QUERY_GATE){
            mTest=new ComponentTest();
            int returnEvent=mTest.getTestInfos(mPipeline,(short)componentId);
            infos=mTest.getTestInfos();
            mStateMachine.resumeStateMachine(returnEvent);  //执行成功，返回执行之后的事件
            return infos;
        }
        mStateMachine.resumeStateMachine(event);    //未执行，返回获取的事件
        return infos;
    }

    public UserAdjustmentStruct setCalibrationValue(int componentId, int tryTimes, int value) {
//        UserAdjustmentStruct result=mCommander.setCalibrationValue(componentId,tryTimes,value);
        int event=mStateMachine.pauseStateMachine();
        UserAdjustmentStruct adjustment=null;
        if(event==StateEventDefine.EVT_NONE||event==StateEventDefine.EVT_QUERY_GATE){
            mTest=new ComponentTest();
            int returnEvent=mTest.putCalibrationValue(mPipeline,(short)componentId,tryTimes,value);
            adjustment=mTest.putCalibrationValue();
            mStateMachine.resumeStateMachine(returnEvent);
            return adjustment;
        }
        mStateMachine.resumeStateMachine(event);
        return adjustment;
    }

    public LocalAdjustmentStruct getCalibrationInfo(int componentId) {
        LocalAdjustmentStruct calInfo = Adjustments.getCalibrationAdjustment(componentId);
        return calInfo;
    }

    public Boolean startMakeProduct(ConfigRecipeStrcut[] recipe, int craftId) {
//        mCommander.startMackeProduct(recipe,craftId);
        int event=mStateMachine.pauseStateMachine();
        if(event==StateEventDefine.EVT_NONE||event==StateEventDefine.EVT_QUERY_GATE){
            int returnEvent=MakeProduct.makeProduct(recipe,craftId,mPipeline);
            mStateMachine.resumeStateMachine(returnEvent);
            return MakeProduct.getProductResult();
        }
        mStateMachine.resumeStateMachine(event);
        return false;
    }

    public float getProducingProgress() {
        return MakeProduct.getStepProgress();
    }

    public int getProducingStatus() {
        return MakeProduct.getProductStatus();
    }

    public List<CraftBriefStruct> getAllCraft(){
        return JobList.getAllCraftDesciption();
    }

    public SparseArray<ComponentStruct> getAllComponents(){
        return Machine.getComponentList();
    }

    public ConfigurableComponentStruct[] getConfigurableComponents(int craftId){
        return Machine.getConfigurableComponents(craftId);
    }

    public Boolean setAllUserAdjustment(UserAdjustmentStruct[] uAdjs) {
//        mCommander.setAllUserAdjustment(uAdjs);
        int event=mStateMachine.pauseStateMachine();
        if(event==StateEventDefine.EVT_NONE||event==StateEventDefine.EVT_QUERY_GATE){
            int returnEvent= Adjustment.setAllUserAdjustment(mPipeline,uAdjs);
            mStateMachine.resumeStateMachine(returnEvent);
            return true;
        }
        mStateMachine.resumeStateMachine(event);    //未执行，返回获取的事件
        return false;
    }

    public LocalAdjustmentStruct[] getComponentAdjustments(int componentId) {
        LocalAdjustmentStruct[] adjs = Adjustments.getAdjustment(componentId);
        return adjs;
    }

    private Version mVersion=new Version();
    public  HardwareVersionStruct[] getHardwareVersion() {
//        return mCommander.getHardwareVersions();
        HardwareVersionStruct[] versions=null;
        int event=mStateMachine.pauseStateMachine();
        if(event==StateEventDefine.EVT_NONE||event==StateEventDefine.EVT_QUERY_GATE){
            int returnEvent=mVersion.getBoardHardwareVersion(mPipeline);
            mStateMachine.resumeStateMachine(returnEvent);
            versions=mVersion.getBoardHardwareVersion();
        }else
            mStateMachine.resumeStateMachine(event);
        if(versions==null){
            versions=new HardwareVersionStruct[1];
            versions[0].boardAdress=0;
            versions[0].version="unknown version";
        }
        return versions;
    }

    public SoftwareVersionStruct[] getSoftwareVersion() {
//        return mCommander.getSoftwareVersions();
        SoftwareVersionStruct[] versions=null;
        int event=mStateMachine.pauseStateMachine();
        if(event==StateEventDefine.EVT_NONE||event==StateEventDefine.EVT_QUERY_GATE){
            int returnEvent= mVersion.getBoardSoftwareVersions(mPipeline);
            mStateMachine.resumeStateMachine(returnEvent);
            versions=mVersion.getBoardSoftwareVersions();
        } else
            mStateMachine.resumeStateMachine(event);
        if(versions==null)
            versions=new SoftwareVersionStruct[0];
        return versions;
    }

    public int updateSoftware(@BoardId.BoardAdress int boardAddress, int type, String filePath) {
//        return mCommander.updateSoftware(boardAddress,type,filePath);
        int event=mStateMachine.pauseStateMachine();
        if(event==StateEventDefine.EVT_NONE||event==StateEventDefine.EVT_QUERY_GATE){
            int returnEvent=mVersion.updateSoftWare(mPipeline,boardAddress,type,filePath);
            mStateMachine.resumeStateMachine(returnEvent);
            return mVersion.getUpdateResult();
        }
        mStateMachine.resumeStateMachine(event);
        return Version.UPDATE_FAILED;
    }

    public int getUpdateProgress() {
//        return mCommander.getUpdateProgress();
        return mVersion.getUpdateProgress();
    }

    public Boolean isThereGateSuspend() {
        return QueryGateStatus.getGlobalGate(GateStatusDefine.GATE_SUSPENDED);
    }

    public Boolean isThereGateDepleted() {
        return QueryGateStatus.getGlobalGate(GateStatusDefine.GATE_DEPLETED);
    }

    public Boolean isThereGateLocked(){
        return QueryGateStatus.getGlobalGate(GateStatusDefine.GATE_LOCKED);
    }

    public Boolean isMachineInit(){
        if(mStateMachine.getCurrentState()== StateDefine.STATE_INIT)
            return true;
        return false;
    }

    public void resetBoard(){
        int event=mStateMachine.pauseStateMachine();
        if(event==StateEventDefine.EVT_NONE||event==StateEventDefine.EVT_QUERY_GATE){
            Service.resetBoard(mPipeline,BoardId.IO_BOARD);
        }
        //mStateMachine.resumeStateMachine(event);
    }

    public void cancelDurationTest(short componentId,short functionId){
        if(mStateMachine.getCurrentState()!=StateDefine.STATE_PAUSE) {
            return;
        }
        isCancelDo=true;
        mTest.shutDownComponentTest(mPipeline); //先终止异步
//        int event=mStateMachine.pauseStateMachine();    //cancel duration
//        if(event==StateEventDefine.EVT_EXECUTE||event==StateEventDefine.EVT_NONE||event==StateEventDefine.EVT_NONE) {
//           int returnEvent=mTest.cancelDurationTest(mPipeline, componentId, functionId);
//            mStateMachine.resumeStateMachine(returnEvent);
//            return;
//        }
//        mStateMachine.resumeStateMachine(returnEvent);
        int returnEvent=mTest.cancelDurationTest(mPipeline, componentId, functionId);
        mStateMachine.resumeStateMachine(returnEvent);
    }

    public List<GateStruct> getUnvaliableComponent() {
        return QueryGateStatus.checkUnusableComponent();
    }

    public TestResultStruct[] dynamicTest(){
        TestResultStruct[] testResult=new TestResultStruct[0];
        int event=mStateMachine.pauseStateMachine();
        if(event==StateEventDefine.EVT_NONE||event==StateEventDefine.EVT_QUERY_GATE){
            int returnEvent=mTest.dynamicComponentTest(mPipeline);
            mStateMachine.resumeStateMachine(returnEvent);
            testResult=mTest.getDynamicTestResult();
            return testResult;
        }
        mStateMachine.resumeStateMachine(event);
        return testResult;
    }

    public void finishBus() {

    }
}
